package com.taichuan.selfcheck.hardware.audio;

import android.media.MediaRecorder;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import com.taichuan.tcutils.common.FileUtils;
import com.taichuan.tcutils.common.TimeUtils;
import com.taichuan.tcutils.taichuan.PrintUtils;

import java.io.File;


/**
 * 该类主要用于 实现 使用 MediaRecorder 类进行声音的录制
 *
 * @author CamelLuo
 * @version 2021/2/4
 */
public class MediaRecordClient {
    private static final String TAG = MediaRecordClient.class.getSimpleName();

    /**
     * 定义一个变量用于表示 是否正在执行执行录音
     */
    private boolean isInRecord = false;

    /**
     * 开始录音 的时间毫秒数
     */
    private long startRecordTime = 0;
    /**
     * 停止录音 的时间毫秒数
     */
    private long endRecordTime = 0;
    /**
     * 录音的持续时间
     */
    private long recordLengthTime = 0;

    private MediaRecorder mRecorder;


    private MediaRecordClient() {

    }

    private static class SingletonHolder{
        private final static MediaRecordClient instance = new MediaRecordClient();
    }

    public static MediaRecordClient getInstance() {
        return SingletonHolder.instance;
    }

    /**
     * 定义一个方法用于执行初始化 多媒体录音类 MediaRecorder
     */
    private void init(){
        mRecorder = new MediaRecorder();
        //设置麦克风作为录音源
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        //设置3gpp格式作为音频文件输出格式
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        //设置AMR_NB格式作为音频编码格式
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        mRecorder.setOnErrorListener((mr, what, extra) -> {
            String content = "自检程序 - setOnErrorListener: 录音发生异常： 错误类型码 what = " + what + " | 额外错误码 extra = " + extra;
            Log.e(TAG, content);
            //进行日志记录
            PrintUtils.get().print(PrintUtils.LogLevel.INFO, TAG, content);
        });
    }

    /**
     * 定义一个方法用于注销 多媒体录音类 相关资源
     */
    public void destroy(){
        try {
            if (mRecorder != null){
                if (isInRecord()){
                    mRecorder.stop();
                    mRecorder.reset();
                }

                mRecorder.release();
                mRecorder = null;

                isInRecord = false;
                startRecordTime = 0;
                endRecordTime = 0;
                recordLengthTime = 0;
            }
        }catch (Exception e){
            e.printStackTrace();
            Log.e(TAG, "destroy: 注销MediaRecorder出现异常： " + e.getMessage());
        }
    }

    /**
     * 定义一个方法用于 开始执行录音
     * @param recordFilePath 录音文件所需要保存的文件路径，需为File文件完整路径
     * @return
     */
    public Pair<Boolean, String> startRecord(String recordFilePath) {
        try {
            if (!isInRecord()) {
                //每次执行录音前均重新进行一次初始化
                init();

                if (mRecorder != null) {
                    if (!TextUtils.isEmpty(recordFilePath)) {
                        //检查传入的录音文件路径是否存在
                        File recordFile = new File(recordFilePath);
                        boolean isSuccess = FileUtils.checkFileAndMakeDirs(recordFile);

                        if (isSuccess) {
                            //设置录音文件输出路径
                            mRecorder.setOutputFile(recordFile.getPath());

                            //为录音做好准备
                            mRecorder.prepare();
                            //开始执行录音
                            mRecorder.start();

                            //记录录音开始时间
                            startRecordTime = System.currentTimeMillis();
                            //重置录音结束时间与时长
                            endRecordTime = 0;
                            recordLengthTime = 0;

                            //更新标志位,进入录音状态
                            setInRecord(true);
                            return new Pair<>(true, "执行成功，开始录音");
                        } else {
                            return new Pair<>(true, "执行失败，传入的录音保存路径不为File");
                        }
                    } else {
                        return new Pair<>(true, "执行失败，传入的录音保存路径为空");
                    }
                } else {
                    return new Pair<>(true, "执行失败，MediaRecorder 实例对象为null");
                }
            } else {
                Log.e(TAG, "startRecord: 设备已处于录音状态，不重复执行");
                return new Pair<>(true, "设备已处于录音状态，不重复执行");
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "startRecord: 启动录音流程执行异常： " + e.getMessage());
            if (mRecorder != null) {
                mRecorder.reset();
                mRecorder.release();
            }
            return new Pair<>(false, "启动录音流程执行异常: " + e.getMessage());
        }
    }

    /**
     * 定义一个方法用于停止录音
     * @return
     */
    public Pair<Boolean,String> stopRecord(){
        try {
            if (isInRecord()){
                if (mRecorder != null){
                    mRecorder.stop();
                    mRecorder.release();

                    //记录录音结束时间
                    endRecordTime = System.currentTimeMillis();
                    //计算录音时长
                    recordLengthTime = endRecordTime - startRecordTime;

                    Log.e(TAG, "stopRecord: 结束录音，本次录音的开始时间为： " + TimeUtils.timeStampToDate(startRecordTime)
                    + " | 结束时间为： " + TimeUtils.timeStampToDate(endRecordTime) +
                            " | 录音时长： " + TimeUtils.getTimeStampRunningDay(recordLengthTime));

                    //更新标志位,退出录音状态
                    setInRecord(false);
                    return new Pair<>(true, "执行成功，停止录音");
                }else {
                    return new Pair<>(true, "执行失败，MediaRecorder 实例对象为null");
                }
            }else {
                Log.e(TAG, "startRecord: 设备不处于录音状态，无需执行停止录音");
                return new Pair<>(true, "设备不处于录音状态，无需执行停止录音");
            }
        }catch (Exception e){
            e.printStackTrace();
            Log.e(TAG, "startRecord: 停止录音流程执行异常： " + e.getMessage());
            if (mRecorder != null){
                mRecorder.reset();
                mRecorder.release();
            }
            return new Pair<>(false, "停止录音流程执行异常: " + e.getMessage());
        }
    }

    /**
     * 定义一个方法用于获取当前 的录音时长
     *
     * @return
     */
    public long getCurrentRecordLengthTime() {
        //处于录音状态时计算录音时长
        if (isInRecord()) {
            recordLengthTime = (System.currentTimeMillis() - startRecordTime)/1000;
            return recordLengthTime;
        } else {
            return 0;
        }
    }

    /**
     * 定义一个方法用于获取当前正在录音时 的录音分贝值
     * @return 分贝值
     */
    public double getRecordDbValue(){
        if (isInRecord()){
            //计算分贝值
            return calculateDb(getRecordMaxAmplitude());
        }else {
            return 0;
        }
    }

    /**
     * 定义一个方法用于获取当前正在录音时的 录音绝对振幅，用于计算分贝值
     *
     * @return 录音绝对振幅
     */
    public int getRecordMaxAmplitude() {
        if (isInRecord()) {
            try {
                return mRecorder.getMaxAmplitude();
            } catch (Exception e) {
                e.printStackTrace();
                Log.e(TAG, "etRecordMaxAmplitude: 获取当前正在录音时的 录音绝对振幅 异常： " + e.getMessage());
                return 0;
            }
        } else {
            return 0;
        }
    }

    /**
     * 定义一个方法用于根据 录音时的 录音绝对振幅值计算 分贝值
     * 公式参考： https://www.jb51.net/article/64806.htm
     * @param maxAmplitude
     * @return
     */
    private double calculateDb(int maxAmplitude) {
        double ratio = (double) maxAmplitude / 1;
        double db = 0;// 分贝
        if (ratio > 1) {
            db = 20 * Math.log10(ratio);
        }
        return db;
    }

    public boolean isInRecord() {
        return isInRecord;
    }

    public void setInRecord(boolean inRecord) {
        isInRecord = inRecord;
    }

}
